﻿#region Header
// Copyright 2007-2011, Jerónimo Milea
// 
// This file is part of NetJsWire.
// 
//     NetJsWire is free software: you can redistribute it and/or modify
//     it under the terms of the GNU General Public License as published by
//     the Free Software Foundation, either version 3 of the License, or
//     (at your option) any later version.
// 
//     NetJsWire is distributed in the hope that it will be useful,
//     but WITHOUT ANY WARRANTY; without even the implied warranty of
//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//     GNU General Public License for more details.
// 
//     You should have received a copy of the GNU General Public License
//     along with NetJsWire.  If not, see <http://www.gnu.org/licenses/>.
#endregion

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Windows.Forms;
using NetJsWire.Lite.Converters;
using NetJsWire.Lite.Designers;
using NetJsWire.Lite.Editors;
using NetJsWire.Lite.Helpers;
using NetJsWire.Lite.Properties;
using NetJsWire.Lite.Widgets.UI.Grid;
using NetJsWire.Lite.Widgets.UI.Layout;
using Newtonsoft.Json;

namespace NetJsWire.Lite.Widgets.UI
{
    [Designer( typeof( ContainerDesigner ) )]
    //[Designer( typeof( PanelDesigner ), typeof( IRootDesigner ) )]
    [ToolboxItem( true )]
    public class Panel : Container
    {
        internal static int ButtonsBarHeight;// = 34;
        internal static int TitleBarHeight;// = 23;
        internal const int DefaultTabWidth = 120;
        internal const int ButtonPadding = 5;
        internal static Color FrameBorderColor = Color.FromArgb( 153, 187, 232 );
        private readonly List<ButtonLW> _buttons = new List<ButtonLW>();
        internal static Color OriginalBackgroundColor = Color.White;
        internal static Color TitleFontColor = Color.FromArgb( 21, 66, 139 );
        internal static Color PanelNCBackgroundColor = Color.FromArgb( 206, 217, 231 );
        internal static Font TitleFont;
        internal static Font UnstyledTitleFont;
        private List<ToolConfig> _toolsInternal = new List<ToolConfig>();
        private ToolbarControl _bbar;
        private bool _bodyBorder = true;
        private bool _border = true;
        private ButtonAlign _buttonAlign = ButtonAlign.Right;
        private bool _closable;
        private bool _collapseFirst = true;
        private bool _collapsible;
        private bool _frame;
        private int _minButtonWidth = 75;
        private bool _shadow;
        private string _title;
        private bool _unstyled;

        public Panel()
            : this( null )
        {
        }

        public Panel( IContainer container )
            : base( container )
        {
            if ( Settings.Default != null )
            {
                PanelNCBackgroundColor = Settings.Default.PanelNCBackgroundColor;
                OriginalBackgroundColor = this is Window ? Settings.Default.WindowBackColor : Settings.Default.BackColor;
                FrameBorderColor = Settings.Default.FrameBorderColor;
                TitleFontColor = Settings.Default.TitleFontColor;
                TitleFont = Settings.Default.PanelTitleFont;
                UnstyledTitleFont = Settings.Default.PanelUnstyledTitleFont;
                ButtonsBarHeight = Settings.Default.ButtonsBarHeight;
                TitleBarHeight = Settings.Default.TitleBarHeight;
            }

            base.BackColor = OriginalBackgroundColor;
            BackgroundColor = PanelNCBackgroundColor;

            base.Xtype = "panel";

            Resize += PanelResize;
        }


        /// <summary>
        ///   <code>true</code> to animate the transition when the panel is collapsed, <code>false</code> to skip the
        ///   animation (defaults to <code>true</code> if the {@link Ext.Fx} class is available, otherwise <code>false</code>).
        /// </summary>
        [JsonProperty( "animCollapse" )]
        [DefaultValue( false )]
        [Description( "true to animate the transition when the panel is collapsed, false to skip the animation." )]
        public virtual bool AnimCollapse { get; set; }

        /// <summary>
        ///   <code>buttons</code> will be used as <code>{@link Ext.Container#items items}</code> for the toolbar in
        ///   the footer (<code>{@link #fbar}</code>). Typically the value of this configuration property will be
        ///   an array of {@link Ext.Button}s or {@link Ext.Button} configuration objects.
        ///   If an item is configured with <code>minWidth</code> or the Panel is configured with <code>minButtonWidth</code>,
        ///   that width will be applied to the item.
        /// </summary>
        [JsonProperty( "buttons", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore )]
        [Browsable( false )]
        [EditorBrowsable( EditorBrowsableState.Advanced )]
        [DefaultValue( null )]
        [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )]
        public List<ButtonLW> Buttons
        {
            get
            {
                try
                {
                    var buttons = Controls.Cast<Control>().Where( c => c is ButtonLW && ( c as ButtonLW ).InButtons );

                    if ( buttons.Count() > 0 )
                    {
                        if ( Site == null || !Site.DesignMode )
                        {
                            _buttons.Clear();
                            foreach ( var btn in buttons.Cast<ButtonLW>().OrderBy( b => b.Location.X ) )
                            {
                                _buttons.Add( btn );
                            }
                            return _buttons;
                        }

                        return buttons.Count() > 0 ? buttons.Cast<ButtonLW>().ToList() : null;
                    }
                }
                catch
                {
                    return null;
                }
                return null;
            }
        }


        /// <summary>
        ///   True to display the borders of the panel's body element, false to hide them (defaults to true).  By default,
        ///   the border is a 2px wide inset border, but this can be further altered by setting {@link #bodyBorder} to false.
        /// </summary>
        [DefaultValue( true )]
        [JsonProperty( "border" )]
        [RefreshProperties( RefreshProperties.Repaint )]
        [Description( "True to display the borders of the panel's body element, false to hide them (defaults to true)." )]
        public virtual bool Border
        {
            get { return _border; }
            set
            {
                _border = value;
                InvalidateWindow();
            }
        }

        /// <summary>
        ///   True to display an interior border on the body element of the panel, false to hide it (defaults to true).
        ///   This only applies when Border = true.  If Border = true and BodyBorder = false, the border will display
        ///   as a 1px wide inset border, giving the entire body element an inset appearance.
        /// </summary>
        [DefaultValue( true )]
        [JsonProperty( "bodyBorder" )]
        [RefreshProperties( RefreshProperties.Repaint )]
        [Description( "True to display an interior border on the body element of the panel, false to hide it (defaults to true)." )]
        public virtual bool BodyBorder
        {
            get { return _bodyBorder; }
            set
            {
                _bodyBorder = value;
                InvalidateWindow();
            }
        }

        /// <summary>
        ///   <code>false</code> by default to render with plain 1px square borders. <code>true</code> to render with
        ///   9 elements, complete with custom rounded corners (also see {@link Ext.Element#boxWrap}).
        ///   <p>The template generated for each condition is depicted below:</p><pre>
        ///                                                                        <code>
        ///                                                                          // frame = false
        ///                                                                          <div id = "developer-specified-id-goes-here" class = "x-panel">
        ///                                                                            <div class = "x-panel-header"><span class = "x-panel-header-text">Title: (frame:false)</span></div>
        ///                                                                            <div class = "x-panel-bwrap">
        ///                                                                              <div class = "x-panel-body"><p>html value goes here</p></div>
        ///                                                                            </div>
        ///                                                                          </div>
        ///                                                                          // frame = true (create 9 elements)
        ///                                                                          <div id = "developer-specified-id-goes-here" class = "x-panel">
        ///                                                                            <div class = "x-panel-tl"><div class = "x-panel-tr"><div class = "x-panel-tc">
        ///                                                                                                                                  <div class = "x-panel-header"><span class = "x-panel-header-text">Title: (frame:true)</span></div>
        ///                                                                                                                                </div></div></div>
        ///                                                                            <div class = "x-panel-bwrap">
        ///                                                                              <div class = "x-panel-ml"><div class = "x-panel-mr"><div class = "x-panel-mc">
        ///                                                                                                                                    <div class = "x-panel-body"><p>html value goes here</p></div>
        ///                                                                                                                                  </div></div></div>
        ///                                                                              <div class = "x-panel-bl"><div class = "x-panel-br"><div class = "x-panel-bc" />
        ///                                                                                                        </div></div></div>
        ///                                                                          </div>
        ///                                                                        </code></pre>
        /// </summary>
        [DefaultValue( false )]
        [JsonProperty( "frame" )]
        [RefreshProperties( RefreshProperties.Repaint )]
        [Description( "false by default to render with plain 1px square borders. true to render with  9 elements, complete with custom rounded corners." )]
        public virtual bool Frame
        {
            get { return _frame; }
            set
            {
                _frame = value;
                if ( value )
                {
                    BackColor = Settings.Default.WindowBackColor;
                }
                else
                {
                    BackColor = OriginalBackgroundColor;
                }
                InvalidateWindow();
            }
        }

        internal override int BorderWidth
        {
            get
            {
                var borderWidth = 0;
                if ( !Unstyled )
                {
                    borderWidth += Border ? 1 : 0;
                    // bodyBorder doesn't seem to be working on Ext ATM
                    // TODO: Check if its working on Ext as expected.
                    //borderWidth += ( Border && BodyBorder ) ? 1 : 0;
                }

                return borderWidth;
            }
        }

        /// <summary>
        ///   True to make the panel collapsible and have the expand/collapse toggle button automatically rendered into
        ///   the header tool button area, false to keep the panel statically sized with no button (defaults to false).
        /// </summary>
        [DefaultValue( false )]
        [JsonProperty( "collapsible" )]
        [RefreshProperties( RefreshProperties.All )]
        [Description( "True to make the panel collapsible and have the expand/collapse toggle button automatically rendered into the header tool button area, false to keep the panel statically sized with no button." )]
        public virtual bool Collapsible
        {
            get { return _collapsible; }
            set
            {
                _collapsible = value;
                InvalidateWindow();
            }
        }

        /// <summary>
        ///   <code>true</code> (or a valid Ext.Shadow {@link Ext.Shadow#mode} value) to display a shadow behind the
        ///   panel, <code>false</code> to display no shadow (defaults to <code>'sides'</code>).  Note that this option
        ///   only applies when <code>{@link #Floating} = true</code>.
        /// </summary>
        [DefaultValue( false )]
        [JsonProperty( "shadow" )]
        [RefreshProperties( RefreshProperties.All )]
        [Description( "true to display a shadow behind the Panel.\nNote that this options only applies when Floating = true" )]
        public virtual bool Shadow
        {
            get { return _shadow; }
            set
            {
                _shadow = value;
                InvalidateWindow();
            }
        }

        internal bool DrawButtonsBar
        {
            get { return Controls.Cast<Control>().Any( c => c is ButtonLW && ( c as ButtonLW ).InButtons ); }
        }

        /// <summary>
        ///   The title text to be used as innerHTML (html tags are accepted) to display in the panel
        ///   <code>{@link #header}</code> (defaults to ''). When a <code>title</code> is specified the
        ///   <code>{@link #header}</code> element will automatically be created and displayed unless
        ///   {@link #header} is explicitly set to <code>false</code>.  If you do not want to specify a
        ///   <code>title</code> at config time, but you may want one later, you must either specify a non-empty
        ///   <code>title</code> (a blank space ' ' will do) or <code>header:true</code> so that the container
        ///   element will get created.
        /// </summary>
        [JsonProperty( "title", DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore )]
        [DefaultValue( ( string ) null )]
        [RefreshProperties( RefreshProperties.All )]
        [Description( "The title text to be used as innerHTML (html tags are accepted) to display in the panel header." )]
        public string Title
        {
            get { return _title; }
            set
            {
                _title = value;
                PerformLayout();
                InvalidateWindow();
            }
        }

        /// <summary>
        ///   The CSS class selector that specifies a background image to be used as the header icon (defaults to '').
        ///   <p>An example of specifying a custom icon class would be something like:
        ///   </p><pre><code>
        ///              // specify the property in the config for the class:
        ///              ...
        ///              iconCls: 'my-icon'
        ///              // css class that specifies background image to be used as the icon image:
        ///              .my-icon { background-image: url(../images/my-icon.gif) 0 6px no-repeat !important; }
        ///            </code></pre>
        /// </summary>
        [JsonProperty( "iconCls", DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore )]
        [DefaultValue( ( string ) null )]
        [Description( "The CSS class selector that specifies a background image to be used as the header icon." )]
        public string IconCls { get; set; }

        /// <summary>
        ///   A {@link Ext.KeyMap} config object (in the format expected by {@link Ext.KeyMap#addBinding}
        ///   used to assign custom key handling to this panel (defaults to <code>null</code>).
        /// </summary>
        [JsonProperty( "keys", DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore )]
        [JsonConverter( typeof( NotQuotedJsonStringConverter ) )]
        [DefaultValue( ( string ) null )]
        [Editor( typeof( ScriptEditor ), typeof( UITypeEditor ) )]
        [Description( "A Ext.KeyMap config object (in the format expected by Ext.KeyMap.addBinding used to assign custom key handling to this panel." )]
        public string Keys { get; set; }

        /// <summary>
        ///   <p>The bottom toolbar of the panel. This can be a {@link Ext.Toolbar} object, a toolbar config, or an array of
        ///     buttons/button configs to be added to the toolbar.  Note that this is not available as a property after render.
        ///     To access the bottom toolbar after render, use {@link #getBottomToolbar}.</p>
        ///   <p><b>Note:</b> Although a Toolbar may contain Field components, these will <b>not</b> be updated by a load
        ///     of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and
        ///     so are not scanned to collect form items. However, the values <b>will</b> be submitted because form
        ///     submission parameters are collected from the DOM tree.</p>
        /// </summary>
        [JsonProperty( "bbar", DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore )]
        [Browsable( true )]
        [DefaultValue( ( string ) null )]
        [Description( "The bottom toolbar of the panel." )]
        public ToolbarControl Bbar
        {
            get { return _bbar; }
            set
            {
                if ( _bbar != null )
                {
                    _bbar.Dock = DockStyle.None;
                    if ( Controls.Contains( _bbar ) )
                    {
                        Controls.Remove( _bbar );

                        if ( Parent != null )
                        {
                            Parent.Controls.Add( _bbar );
                            Parent.PerformLayout();
                        }
                    }
                }

                _bbar = value;

                if ( _bbar != null )
                {
                    if ( !Controls.Contains( _bbar ) )
                    {
                        if ( _bbar.Parent != null )
                        {
                            _bbar.Parent.Controls.Remove( _bbar );
                        }

                        Controls.Add( _bbar );
                    }
                    _bbar.Dock = DockStyle.Bottom;

                    PositionBars();
                }

                InvalidateWindow();
            }
        }


        /// <summary>
        ///   <p>The top toolbar of the panel. This can be a {@link Ext.Toolbar} object, a toolbar config, or an array of
        ///     buttons/button configs to be added to the toolbar.  Note that this is not available as a property after render.
        ///     To access the top toolbar after render, use {@link #getTopToolbar}.</p>
        ///   <p><b>Note:</b> Although a Toolbar may contain Field components, these will <b>not</b> be updated by a load
        ///     of an ancestor FormPanel. A Panel's toolbars are not part of the standard Container->Component hierarchy, and
        ///     so are not scanned to collect form items. However, the values <b>will</b> be submitted because form
        ///     submission parameters are collected from the DOM tree.</p>
        /// </summary>
        [JsonProperty( "tbar", DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore )]
        [JsonConverter( typeof( NotQuotedJsonStringConverter ) )]
        [DefaultValue( ( string ) null )]
        [Editor( typeof( ScriptEditor ), typeof( UITypeEditor ) )]
        [Description( "The top toolbar of the panel. This can be a ToolbarControl object, a toolbar config, or an array of buttons/button configs to be added to the toolbar." )]
        public string Tbar { get; set; }

        [JsonProperty( "fbar", DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore )]
        [JsonConverter( typeof( NotQuotedJsonStringConverter ) )]
        [DefaultValue( ( string ) null )]
        [Editor( typeof( ScriptEditor ), typeof( UITypeEditor ) )]
        [Description( "A Toolbar object, a Toolbar config, or an array of Buttons/Button configs, describing a Toolbar to be rendered into this Panel's footer element." )]
        public string Fbar { get; set; }

        /// <summary>
        ///   Panels themselves do not directly support being closed, but some Panel subclasses do (like
        ///   {@link Ext.Window}) or a Panel Class within an {@link Ext.TabPanel}.  Specify <code>true</code>
        ///   to enable closing in such situations. Defaults to <code>false</code>.
        /// </summary>
        [DefaultValue( false )]
        [JsonProperty( "closable" )]
        [RefreshProperties( RefreshProperties.Repaint )]
        [Description( "Panels themselves do not directly support being closed, but some Panel subclasses do (like Ext.Window) or a Panel Class within an Ext.TabPanel. Specify true to enable closing in such situations. Defaults to false." )]
        public virtual bool Closable
        {
            get { return _closable; }
            set
            {
                _closable = value;
                InvalidateWindow();
            }
        }

        /// <summary>
        ///   Overrides the <code>{@link #baseCls}</code> setting to <code>{@link #baseCls} = 'x-plain'</code> which renders
        ///   the panel unstyled except for required attributes for Ext layouts to function (e.g. overflow:hidden).
        /// </summary>
        [DefaultValue( false )]
        [JsonProperty( "unstyled" )]
        [RefreshProperties( RefreshProperties.Repaint )]
        [Description( "Overrides the baseCls setting to baseCls = 'x-plain' which renders the panel unstyled except for required attributes for Ext layouts to function (e.g. overflow:hidden)." )]
        public virtual bool Unstyled
        {
            get { return _unstyled; }
            set
            {
                _unstyled = value;
                if ( Parent != null )
                {
                    if ( value )
                    {
                        BackColor = Parent.BackColor;
                        BackgroundColor = Parent.BackColor;
                    }
                    else
                    {
                        BackColor = OriginalBackgroundColor;
                        BackgroundColor = OriginalBackgroundColor;
                    }
                }
                InvalidateWindow();
                Invalidate( true );
            }
        }

        /// <summary>
        ///   A shortcut for setting a padding style on the body element. The value can either be
        ///   a number to be applied to all sides, or a normal css string describing padding.
        ///   Defaults to <tt>undefined</tt>.
        /// </summary>
        [JsonProperty( "padding" )]
        [Description( "A shortcut for setting a padding style on the body element." )]
        [Browsable( true ), EditorBrowsable]
        [JsonConverter( typeof( PaddingJsonConverter ) )]
        [RefreshProperties( RefreshProperties.Repaint )]
        public new Padding Padding
        {
            get { return base.Padding; }
            set { base.Padding = value; }
        }

        /// <summary>
        ///   The base CSS class to apply to this panel's element (defaults to <code>'x-panel'</code>).
        ///   <p>Another option available by default is to specify <code>'x-plain'</code> which strips all styling
        ///     except for required attributes for Ext layouts to function (e.g. overflow:hidden).
        ///     See <code>{@link #unstyled}</code> also.</p>
        /// </summary>
        [JsonProperty( "baseCls" )]
        [DefaultValue( ( string ) null )]
        [Description( "The base CSS class to apply to this panel's element" )]
        public virtual string BaseCls { get; set; }

        /// <summary>
        ///   <p>A {@link Ext.DomHelper DomHelper} element specification object may be specified for any
        ///     Panel Element.</p>
        ///   <p>By default, the Default element in the table below will be used for the html markup to
        ///     create a child element with the commensurate Default class name (<code>baseCls</code> will be
        ///     replaced by <code>{@link #baseCls}</code>):</p>
        ///   <pre>
        ///     Panel      Default  Default             Custom      Additional       Additional
        ///     Element    element  class               element     class            style
        ///     ========   ==========================   =========   ==============   ===========
        ///     {@link #header}     div      {@link #baseCls}+'-header'   {@link #headerCfg}   headerCssClass   headerStyle
        ///     {@link #bwrap}      div      {@link #baseCls}+'-bwrap'     {@link #bwrapCfg}    bwrapCssClass    bwrapStyle
        ///     + tbar     div      {@link #baseCls}+'-tbar'       {@link #tbarCfg}     tbarCssClass     tbarStyle
        ///     + {@link #body}     div      {@link #baseCls}+'-body'       {@link #bodyCfg}     {@link #bodyCssClass}     {@link #bodyStyle}
        ///     + bbar     div      {@link #baseCls}+'-bbar'       {@link #bbarCfg}     bbarCssClass     bbarStyle
        ///     + {@link #footer}   div      {@link #baseCls}+'-footer'   {@link #footerCfg}   footerCssClass   footerStyle
        ///   </pre>
        ///   <p>Configuring a Custom element may be used, for example, to force the {@link #body} Element
        ///     to use a different form of markup than is created by default. An example of this might be
        ///     to {@link Ext.Element#createChild create a child} Panel containing a custom content, such as
        ///     a header, or forcing centering of all Panel content by having the body be a
        ///   </p>
        ///   <pre><code>
        ///          new Ext.Panel({
        ///          title: 'Message Title',
        ///          renderTo: Ext.getBody(),
        ///          width: 200, height: 130,
        ///          <b>bodyCfg</b>: {
        ///          tag: 'center',
        ///          cls: 'x-panel-body',  // Default class not applied if Custom element specified
        ///          html: 'Message'
        ///          },
        ///          footerCfg: {
        ///          tag: 'h2',
        ///          cls: 'x-panel-footer',        // same as the Default class
        ///          html: 'footer html'
        ///          },
        ///          footerCssClass: 'custom-footer', // additional css class, see {@link Ext.element#addClass addClass}
        ///          footerStyle:    'background-color:red' // see {@link #bodyStyle}
        ///          });
        ///        </code></pre>
        ///   <p>The example above also explicitly creates a <code>{@link #footer}</code> with custom markup and
        ///     styling applied.</p>
        /// </summary>
        [JsonProperty( "bodyCfg" )]
        [Editor( typeof( ScriptEditor ), typeof( UITypeEditor ) )]
        [JsonConverter( typeof( NotQuotedJsonStringConverter ) )]
        [DefaultValue( ( string ) null )]
        [Description( "A DomHelper element specification object may be specified for any Panel Element." )]
        public string BodyCfg { get; set; }

        /// <summary>
        ///   <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
        ///     of this Panel's {@link #header} Element.  See <code>{@link #bodyCfg}</code> also.</p>
        /// </summary>
        [JsonProperty( "headerCfg" )]
        [Editor( typeof( ScriptEditor ), typeof( UITypeEditor ) )]
        [JsonConverter( typeof( NotQuotedJsonStringConverter ) )]
        [DefaultValue( ( string ) null )]
        [Description( "A DomHelper element specification object specifying the element structure of this Panel's header Element." )]
        public string HeaderCfg { get; set; }

        /// <summary>
        ///   <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
        ///     of this Panel's {@link #bwrap} Element.  See <code>{@link #bodyCfg}</code> also.</p>
        /// </summary>
        [JsonProperty( "bwrapCfg" )]
        [Editor( typeof( ScriptEditor ), typeof( UITypeEditor ) )]
        [JsonConverter( typeof( NotQuotedJsonStringConverter ) )]
        [DefaultValue( ( string ) null )]
        [Description( "A DomHelper element specification object specifying the element structure of this Panel's bwrap Element." )]
        public string BwrapCfg { get; set; }

        /// <summary>
        ///   <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
        ///     of this Panel's {@link #tbar} Element.  See <code>{@link #bodyCfg}</code> also.</p>
        /// </summary>
        [JsonProperty( "tbarCfg" )]
        [Editor( typeof( ScriptEditor ), typeof( UITypeEditor ) )]
        [JsonConverter( typeof( NotQuotedJsonStringConverter ) )]
        [DefaultValue( ( string ) null )]
        [Description( "A DomHelper element specification object specifying the element structure of this Panel's tbar Element." )]
        public string TbarCfg { get; set; }

        /// <summary>
        ///   <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
        ///     of this Panel's {@link #bbar} Element.  See <code>{@link #bodyCfg}</code> also.</p>
        /// </summary>
        [JsonProperty( "bbarCfg" )]
        [Editor( typeof( ScriptEditor ), typeof( UITypeEditor ) )]
        [JsonConverter( typeof( NotQuotedJsonStringConverter ) )]
        [DefaultValue( ( string ) null )]
        [Description( "A DomHelper element specification object specifying the element structure of this Panel's bbar Element." )]
        public string BbarCfg { get; set; }

        /// <summary>
        ///   <p>A {@link Ext.DomHelper DomHelper} element specification object specifying the element structure
        ///     of this Panel's {@link #footer} Element.  See <code>{@link #bodyCfg}</code> also.</p>
        /// </summary>
        [JsonProperty( "footerCfg" )]
        [Editor( typeof( ScriptEditor ), typeof( UITypeEditor ) )]
        [JsonConverter( typeof( NotQuotedJsonStringConverter ) )]
        [DefaultValue( ( string ) null )]
        [Description( "A DomHelper element specification object specifying the element structure of this Panel's footer Element." )]
        public string FooterCfg { get; set; }

        /// <summary>
        ///   <p>The id of the node, a DOM node or an existing Element corresponding to a DIV that is already present in
        ///     the document that specifies some panel-specific structural markup.  When <code>applyTo</code> is used,
        ///     constituent parts of the panel can be specified by CSS class name within the main element, and the panel
        ///     will automatically create those components from that markup. Any required components not specified in the
        ///     markup will be autogenerated if necessary.</p>
        ///   <p>The following class names are supported (baseCls will be replaced by {@link #baseCls}):</p>
        ///   <ul><li>baseCls + '-header'</li>
        ///     <li>baseCls + '-header-text'</li>
        ///     <li>baseCls + '-bwrap'</li>
        ///     <li>baseCls + '-tbar'</li>
        ///     <li>baseCls + '-body'</li>
        ///     <li>baseCls + '-bbar'</li>
        ///     <li>baseCls + '-footer'</li></ul>
        ///   <p>Using this config, a call to render() is not required.  If applyTo is specified, any value passed for
        ///     {@link #renderTo} will be ignored and the target element's parent node will automatically be used as the
        ///     panel's container.</p>
        /// </summary>
        [JsonProperty( "applyTo" )]
        [JsonConverter( typeof( NotQuotedJsonStringConverter ) )]
        [DefaultValue( ( string ) null )]
        [Description( "The id of the node, a DOM node or an existing Element corresponding to a DIV that is already present in the document that specifies some panel-specific structural markup. When applyTo is used, constituent parts of the panel can be specified by CSS class name within the main element, and the panel will automatically create those components from that markup. Any required components not specified in the markup will be autogenerated if necessary." )]
        public string ApplyTo { get; set; }

        /// <summary>
        ///   A valid url spec according to the Updater {@link Ext.Updater#update} method.
        ///   If autoLoad is not null, the panel will attempt to load its contents
        ///   immediately upon render.<p>
        ///                             The URL will become the default URL for this panel's {@link #body} element,
        ///                             so it may be {@link Ext.Element#refresh refresh}ed at any time.</p>
        /// </summary>
        [JsonProperty( "autoLoad" )]
        [Editor( typeof( ScriptEditor ), typeof( UITypeEditor ) )]
        [JsonConverter( typeof( NotQuotedJsonStringConverter ) )]
        [DefaultValue( ( string ) null )]
        [Description( "A valid url spec according to the Updater Ext.Updater.update method. If autoLoad is not null, the panel will attempt to load its contents immediately upon render.\nThe URL will become the default URL for this panel's body element, so it may be refreshed at any time." )]
        public string AutoLoad { get; set; }

        /// <summary>
        ///   Additional css class selector to be applied to the {@link #body} element in the format expected by
        ///   {@link Ext.Element#addClass} (defaults to null). See {@link #bodyCfg}.
        /// </summary>
        [JsonProperty( "bodyCssClass" )]
        [Editor( typeof( ScriptEditor ), typeof( UITypeEditor ) )]
        [JsonConverter( typeof( NotQuotedJsonStringConverter ) )]
        [DefaultValue( ( string ) null )]
        [Description( "Additional css class selector to be applied to the body element in the format expected by Ext.Element.addClass (defaults to null)." )]
        public string BodyCssClass { get; set; }

        /// <summary>
        ///   Custom CSS styles to be applied to the {@link #body} element in the format expected by
        ///   {@link Ext.Element#applyStyles} (defaults to null). See {@link #bodyCfg}.
        /// </summary>
        [JsonProperty( "bodyStyle" )]
        [Editor( typeof( ScriptEditor ), typeof( UITypeEditor ) )]
        [JsonConverter( typeof( NotQuotedJsonStringConverter ) )]
        [DefaultValue( ( string ) null )]
        [Description( "Custom CSS styles to be applied to the body element in the format expected by Ext.Element.applyStyles (defaults to null)." )]
        public string BodyStyle { get; set; }

        /// <summary>
        ///   An array of tool button configs to be added to the header tool area. When rendered, each tool is
        ///   stored as an {@link Ext.Element Element} referenced by a public property called <code><b></b>tools.<i>&lt;tool-type&gt;</i></code>
        ///   <p>Each tool config may contain the following properties:
        ///     <div class = "mdetail-params"><ul>
        ///                                     <li><b>id</b> : String<div class = "sub-desc"><b>Required.</b> The type
        ///                                                             of tool to create. By default, this assigns a CSS class of the form <code>x-tool-<i>&lt;tool-type&gt;</i></code> to the
        ///                                                             resulting tool Element. Ext provides CSS rules, and an icon sprite containing images for the tool types listed below.
        ///                                                             The developer may implement custom tools by supplying alternate CSS rules and background images:
        ///                                                             <ul>
        ///                                                               <div class = "x-tool x-tool-toggle" style = "float:left; margin-right:5;"> </div><div><code> toggle</code> (Created by default when {@link #collapsible} is <code>true</code>)</div>
        ///                                                               <div class = "x-tool x-tool-close" style = "float:left; margin-right:5;"> </div><div><code> close</code></div>
        ///                                                               <div class = "x-tool x-tool-minimize" style = "float:left; margin-right:5;"> </div><div><code> minimize</code></div>
        ///                                                               <div class = "x-tool x-tool-maximize" style = "float:left; margin-right:5;"> </div><div><code> maximize</code></div>
        ///                                                               <div class = "x-tool x-tool-restore" style = "float:left; margin-right:5;"> </div><div><code> restore</code></div>
        ///                                                               <div class = "x-tool x-tool-gear" style = "float:left; margin-right:5;"> </div><div><code> gear</code></div>
        ///                                                               <div class = "x-tool x-tool-pin" style = "float:left; margin-right:5;"> </div><div><code> pin</code></div>
        ///                                                               <div class = "x-tool x-tool-unpin" style = "float:left; margin-right:5;"> </div><div><code> unpin</code></div>
        ///                                                               <div class = "x-tool x-tool-right" style = "float:left; margin-right:5;"> </div><div><code> right</code></div>
        ///                                                               <div class = "x-tool x-tool-left" style = "float:left; margin-right:5;"> </div><div><code> left</code></div>
        ///                                                               <div class = "x-tool x-tool-up" style = "float:left; margin-right:5;"> </div><div><code> up</code></div>
        ///                                                               <div class = "x-tool x-tool-down" style = "float:left; margin-right:5;"> </div><div><code> down</code></div>
        ///                                                               <div class = "x-tool x-tool-refresh" style = "float:left; margin-right:5;"> </div><div><code> refresh</code></div>
        ///                                                               <div class = "x-tool x-tool-minus" style = "float:left; margin-right:5;"> </div><div><code> minus</code></div>
        ///                                                               <div class = "x-tool x-tool-plus" style = "float:left; margin-right:5;"> </div><div><code> plus</code></div>
        ///                                                               <div class = "x-tool x-tool-help" style = "float:left; margin-right:5;"> </div><div><code> help</code></div>
        ///                                                               <div class = "x-tool x-tool-search" style = "float:left; margin-right:5;"> </div><div><code> search</code></div>
        ///                                                               <div class = "x-tool x-tool-save" style = "float:left; margin-right:5;"> </div><div><code> save</code></div>
        ///                                                               <div class = "x-tool x-tool-print" style = "float:left; margin-right:5;"> </div><div><code> print</code></div>
        ///                                                             </ul></div></li>
        ///                                     <li><b>handler</b> : Function<div class = "sub-desc"><b>Required.</b> The function to
        ///                                                                    call when clicked. Arguments passed are:<ul>
        ///                                                                                                              <li><b>event</b> : Ext.EventObject<div class = "sub-desc">The click event.</div></li>
        ///                                                                                                              <li><b>toolEl</b> : Ext.Element<div class = "sub-desc">The tool Element.</div></li>
        ///                                                                                                              <li><b>panel</b> : Ext.Panel<div class = "sub-desc">The host Panel</div></li>
        ///                                                                                                              <li><b>tc</b> : Object<div class = "sub-desc">The tool configuration object</div></li>
        ///                                                                                                            </ul></div></li>
        ///                                     <li><b>stopEvent</b> : Boolean<div class = "sub-desc">Defaults to true. Specify as false to allow click event to propagate.</div></li>
        ///                                     <li><b>scope</b> : Object<div class = "sub-desc">The scope in which to call the handler.</div></li>
        ///                                     <li><b>qtip</b> : String/Object<div class = "sub-desc">A tip string, or
        ///                                                                      a config argument to {@link Ext.QuickTip#register}</div></li>
        ///                                     <li><b>hidden</b> : Boolean<div class = "sub-desc">True to initially render hidden.</div></li>
        ///                                     <li><b>on</b> : Object<div class = "sub-desc">A listener config object specifiying
        ///                                                             event listeners in the format of an argument to {@link #addListener}</div></li>
        ///                                   </ul></div>
        ///     <p>Note that, apart from the toggle tool which is provided when a panel is collapsible, these
        ///       tools only provide the visual button. Any required functionality must be provided by adding
        ///       handlers that implement the necessary behavior.</p>
        ///     <p>Example usage:</p>
        ///     <pre><code>
        ///            tools:[{
        ///            id:'refresh',
        ///            qtip: 'Refresh form Data',
        ///            // hidden:true,
        ///            handler: function(event, toolEl, panel){
        ///            // refresh logic
        ///            }
        ///            },
        ///            {
        ///            id:'help',
        ///            qtip: 'Get Help',
        ///            handler: function(event, toolEl, panel){
        ///            // whatever
        ///            }
        ///            }]
        ///          </code></pre>
        ///     <p>For the custom id of <code>'help'</code> define two relevant css classes with a link to
        ///       a 15x15 image:</p>
        ///     <pre><code>
        ///            .x-tool-help {background-image: url(images/help.png);}
        ///            .x-tool-help-over {background-image: url(images/help_over.png);}
        ///            // if using an image sprite:
        ///            .x-tool-help {background-image: url(images/help.png) no-repeat 0 0;}
        ///            .x-tool-help-over {background-position:-15px 0;}
        ///          </code></pre></p>
        /// </summary>
        [JsonProperty( "tools" )]
        [Description( "An array of tool button configs to be added to the header tool area. When rendered, each tool is stored as an Element referenced by a public property called tools.<tool-type>" )]
        public List<ToolConfig> Tools
        {
            get { return _toolsInternal; }
            set { _toolsInternal = value; }
        }

        /// <summary>
        ///   <p>A Template used to create {@link #tools} in the {@link #header} Element. Defaults to:</p><pre><code>
        ///                                                                                                      new Ext.Template('<div class = "x-tool x-tool-{id}">&amp;#160;</div>')</code></pre>
        ///   <p>This may may be overridden to provide a custom DOM structure for tools based upon a more
        ///     complex XTemplate. The template's data is a single tool configuration object (Not the entire Array)
        ///     as specified in {@link #tools}.  In the following example an &lt;a&gt; tag is used to provide a
        ///     visual indication when hovering over the tool:</p><pre><code>
        ///                                                              var win = new Ext.Window({
        ///                                                              tools: [{
        ///                                                              id: 'download',
        ///                                                              href: '/MyPdfDoc.pdf'
        ///                                                              }],
        ///                                                              toolTemplate: new Ext.XTemplate(
        ///                                                              '<tpl if = "id==\'download\'">',
        ///                                                                 '<a class = "x-tool x-tool-pdf" href = "{href}"></a>',
        ///                                                                 '</tpl>',
        ///                                                              '<tpl if = "id!=\'download\'">',
        ///                                                                 '<div class = "x-tool x-tool-{id}">&amp;#160;</div>',
        ///                                                                 '</tpl>'
        ///                                                              ),
        ///                                                              width:500,
        ///                                                              height:300,
        ///                                                              closeAction:'hide'
        ///                                                              });</code></pre>
        ///   <p>Note that the CSS class 'x-tool-pdf' should have an associated style rule which provides an
        ///     appropriate background image, something like:</p>
        ///   <pre><code>
        ///          a.x-tool-pdf {background-image: url(../shared/extjs/images/pdf.gif)!important;}
        ///        </code></pre>
        /// </summary>
        [JsonProperty( "toolTemplate" )]
        [Editor( typeof( ScriptEditor ), typeof( UITypeEditor ) )]
        [JsonConverter( typeof( NotQuotedJsonStringConverter ) )]
        [DefaultValue( ( string ) null )]
        [Description( "A Template used to create tools in the header Element." )]
        public string ToolTemplate { get; set; }

        /// <summary>
        ///   <code>true</code> to hide the expand/collapse toggle button when <code>{@link #collapsible} == true</code>,
        ///   <code>false</code> to display it (defaults to <code>false</code>).
        /// </summary>
        [JsonProperty( "hideCollapseTool" )]
        [DefaultValue( false )]
        [Description( "true to hide the expand/collapse toggle button when collapsible == true, false to display it (defaults to false)." )]
        public bool HideCollapseTool { get; set; }

        /// <summary>
        ///   <code>true</code> to allow expanding and collapsing the panel (when <code>{@link #collapsible} = true</code>)
        ///   by clicking anywhere in the header bar, <code>false</code>) to allow it only by clicking to tool button
        ///   (defaults to <code>false</code>)). If this panel is a child item of a border layout also see the
        ///   {@link Ext.layout.BorderLayout.Region BorderLayout.Region}
        ///   <code>{@link Ext.layout.BorderLayout.Region#floatable floatable}</code> config option.
        /// </summary>
        [JsonProperty( "titleCollapse" )]
        [DefaultValue( false )]
        [Description( "true to allow expanding and collapsing the panel (when collapsible = true) by clicking anywhere in the header bar, false) to allow it only by clicking to tool button (defaults to false))." )]
        public bool TitleCollapse { get; set; }

        /// <summary>
        ///   <p>This property is used to configure the underlying {@link Ext.Layer}. Acceptable values for this
        ///     configuration property are:</p><div class = "mdetail-params"><ul>
        ///                                                                    <li><b><code>false</code></b> : <b>Default.</b><div class = "sub-desc">Display the panel inline where it is
        ///                                                                                                                     rendered.</div></li>
        ///                                                                    <li><b><code>true</code></b> : <div class = "sub-desc">Float the panel (absolute position it with automatic
        ///                                                                                                     shimming and shadow).<ul>
        ///                                                                                                                            <div class = "sub-desc">Setting floating to true will create an Ext.Layer for this panel and display the
        ///                                                                                                                              panel at negative offsets so that it is hidden.</div>
        ///                                                                                                                            <div class = "sub-desc">Since the panel will be absolute positioned, the position must be set explicitly
        ///                                                                                                                              <i>after</i> render (e.g., <code>myPanel.setPosition(100,100);</code>).</div>
        ///                                                                                                                            <div class = "sub-desc"><b>Note</b>: when floating a panel you should always assign a fixed width,
        ///                                                                                                                              otherwise it will be auto width and will expand to fill to the right edge of the viewport.</div>
        ///                                                                                                                          </ul></div></li>
        ///                                                                    <li><b><code>{@link Ext.Layer object}</code></b> : <div class = "sub-desc">The specified object will be used
        ///                                                                                                                         as the configuration object for the {@link Ext.Layer} that will be created.</div></li>
        ///                                                                  </ul></div>
        /// </summary>
        [JsonProperty( "floating" )]
        [Editor( typeof( ScriptEditor ), typeof( UITypeEditor ) )]
        [JsonConverter( typeof( NotQuotedJsonStringConverter ) )]
        [DefaultValue( ( string ) null )]
        [Description( "This property is used to configure the underlying Ext.Layer." )]
        public string Floating { get; set; }

        /// <summary>
        ///   The number of pixels to offset the shadow if displayed (defaults to <code>4</code>). Note that this
        ///   option only applies when <code>{@link #floating} = true</code>.
        /// </summary>
        [JsonProperty( "shadowOffset" )]
        [DefaultValue( 0 )]
        [Description( "The number of pixels to offset the shadow if displayed (defaults to 4). Note that this option only applies when floating = true." )]
        public int ShadowOffset { get; set; }

        /// <summary>
        ///   <code>false</code> to disable the iframe shim in browsers which need one (defaults to <code>true</code>).
        ///   Note that this option only applies when <code>{@link #floating} = true</code>.
        /// </summary>
        [JsonProperty( "shim" )]
        [DefaultValue( false )]
        [Description( "false to disable the iframe shim in browsers which need one (defaults to true). Note that this option only applies when floating = true." )]
        public bool Shim { get; set; }


        /// <summary>
        ///   <p><code>true</code> to enable dragging of this Panel (defaults to <code>false</code>).</p>
        ///   <p>For custom drag/drop implementations, an <b>Ext.Panel.DD</b> config could also be passed
        ///     in this config instead of <code>true</code>. Ext.Panel.DD is an internal, undocumented class which
        ///     moves a proxy Element around in place of the Panel's element, but provides no other behaviour
        ///     during dragging or on drop. It is a subclass of {@link Ext.dd.DragSource}, so behaviour may be
        ///     added by implementing the interface methods of {@link Ext.dd.DragDrop} e.g.:
        ///     <pre><code>
        ///            new Ext.Panel({
        ///            title: 'Drag me',
        ///            x: 100,
        ///            y: 100,
        ///            renderTo: Ext.getBody(),
        ///            floating: true,
        ///            frame: true,
        ///            width: 400,
        ///            height: 200,
        ///            draggable: {
        ///            //      Config option of Ext.Panel.DD class.
        ///            //      It&#39;s a floating Panel, so do not show a placeholder proxy in the original position.
        ///            insertProxy: false,
        ///            //      Called for each mousemove event while dragging the DD object.
        ///            onDrag : function(e){
        ///            //          Record the x,y position of the drag proxy so that we can
        ///            //          position the Panel at end of drag.
        ///            var pel = this.proxy.getEl();
        ///            this.x = pel.getLeft(true);
        ///            this.y = pel.getTop(true);
        ///            //          Keep the Shadow aligned if there is one.
        ///            var s = this.panel.getEl().shadow;
        ///            if (s) {
        ///            s.realign(this.x, this.y, pel.getWidth(), pel.getHeight());
        ///            }
        ///            },
        ///            //      Called on the mouseup event.
        ///            endDrag : function(e){
        ///            this.panel.setPosition(this.x, this.y);
        ///            }
        ///            }
        ///            }).show();
        ///          </code></pre></p>
        /// </summary>
        [JsonProperty( "draggable" )]
        [Editor( typeof( ScriptEditor ), typeof( UITypeEditor ) )]
        [JsonConverter( typeof( NotQuotedJsonStringConverter ) )]
        [DefaultValue( ( string ) null )]
        [Description( "true to enable dragging of this Panel (defaults to false)." )]
        public string Draggable { get; set; }

        /// <summary>
        ///   Render this panel disabled (default is <code>false</code>). An important note when using the disabled
        ///   config on panels is that IE will often fail to initialize the disabled mask element correectly if
        ///   the panel's layout has not yet completed by the time the Panel is disabled during the render process.
        ///   If you experience this issue, you may need to instead use the {@link #afterlayout} event to initialize
        ///   the disabled state:
        ///   <pre><code>
        ///          new Ext.Panel({
        ///          ...
        ///          listeners: {
        ///          'afterlayout': {
        ///          fn: function(p){
        ///          p.disable();
        ///          },
        ///          single: true // important, as many layouts can occur
        ///          }
        ///          }
        ///          });
        ///        </code></pre>
        /// </summary>
        [JsonProperty( "disabled" )]
        [DefaultValue( false )]
        [Description( "Render this panel disabled (default is false)." )]
        public override bool Disabled { get; set; }

        /// <summary>
        ///   <code>true</code> to use height:'auto', <code>false</code> to use fixed height (defaults to <code>false</code>).
        ///   <b>Note</b>: Setting <code>autoHeight: true</code> means that the browser will manage the panel's height
        ///   based on its contents, and that Ext will not manage it at all. If the panel is within a layout that
        ///   manages dimensions (<code>fit</code>, <code>border</code>, etc.) then setting <code>autoHeight: true</code>
        ///   can cause issues with scrolling and will not generally work as expected since the panel will take
        ///   on the height of its contents rather than the height required by the Ext layout.
        /// </summary>
        [JsonProperty( "autoHeight" )]
        [DefaultValue( false )]
        [Description( "true to use height:'auto', false to use fixed height (defaults to false)." )]
        public bool AutoHeight { get; set; }

        /// <summary>
        ///   A CSS class to add to the panel's element after it has been collapsed (defaults to
        ///   <code>'x-panel-collapsed'</code>).
        /// </summary>
        [JsonProperty( "collapsedCls" )]
        [DefaultValue( ( string ) null )]
        [Description( "A CSS class to add to the panel's element after it has been collapsed (defaults to 'x-panel-collapsed')." )]
        public string CollapsedCls { get; set; }

        /// <summary>
        ///   <code>true</code> to mask the panel when it is {@link #disabled}, <code>false</code> to not mask it (defaults
        ///   to <code>true</code>).  Either way, the panel will always tell its contained elements to disable themselves
        ///   when it is disabled, but masking the panel can provide an additional visual cue that the panel is
        ///   disabled.
        /// </summary>
        [JsonProperty( "maskDisabled" )]
        [DefaultValue( false )]
        [Description( "true to mask the panel when it is disabled, false to not mask it (defaults to true). Either way, the panel will always tell its contained elements to disable themselves when it is disabled, but masking the panel can provide an additional visual cue that the panel is disabled." )]
        public bool MaskDisabled { get; set; }

        /// <summary>
        ///   <code>true</code> to display the panel <code>{@link #title}</code> in the <code>{@link #header}</code>,
        ///   <code>false</code> to hide it (defaults to <code>true</code>).
        /// </summary>
        [JsonProperty( "headerAsText" )]
        [DefaultValue( true )]
        [Description( "true to display the panel title in the header, false to hide it (defaults to true)." )]
        public bool HeaderAsText
        {
            get { return _headerAsText; }
            set { _headerAsText = value; }
        }
        private bool _headerAsText = true;

        /// <summary>
        ///   The alignment of any {@link #buttons} added to this panel.  Valid values are <code>'right'</code>,
        ///   <code>'left'</code> and <code>'center'</code> (defaults to <code>'right'</code>).
        /// </summary>
        [JsonProperty( "buttonAlign" )]
        [DefaultValue( ButtonAlign.Right )]
        [JsonConverter( typeof( LowerCaseEnumConverter ) )]
        [Description( "The alignment of any buttons added to this panel. Valid values are 'right', 'left' and 'center' (defaults to 'right')." )]
        public ButtonAlign ButtonAlign
        {
            get { return _buttonAlign; }
            set { _buttonAlign = value; }
        }

        /// <summary>
        ///   <code>true</code> to make sure the collapse/expand toggle button always renders first (to the left of)
        ///   any other tools in the panel's title bar, <code>false</code> to render it last (defaults to <code>true</code>).
        /// </summary>
        [JsonProperty( "collapseFirst" )]
        [DefaultValue( true )]
        [Description( "true to make sure the collapse/expand toggle button always renders first (to the left of) any other tools in the panel's title bar, false to render it last (defaults to true)." )]
        public bool CollapseFirst
        {
            get { return _collapseFirst; }
            set { _collapseFirst = value; }
        }

        /// <summary>
        ///   Minimum width in pixels of all {@link #buttons} in this panel (defaults to <code>75</code>)
        /// </summary>
        [JsonProperty( "minButtonWidth" )]
        [DefaultValue( 75 )]
        [Description( "Minimum width in pixels of all buttons in this panel (defaults to 75)" )]
        public int MinButtonWidth
        {
            get { return _minButtonWidth; }
            set { _minButtonWidth = value; }
        }

        /// <summary>
        ///   A comma-delimited list of panel elements to initialize when the panel is rendered.  Normally, this list will be
        ///   generated automatically based on the items added to the panel at config time, but sometimes it might be useful to
        ///   make sure a structural element is rendered even if not specified at config time (for example, you may want
        ///   to add a button or toolbar dynamically after the panel has been rendered).  Adding those elements to this
        ///   list will allocate the required placeholders in the panel when it is rendered.  Valid values are<div class = "mdetail-params"><ul>
        ///                                                                                                                                   <li><code>header</code></li>
        ///                                                                                                                                   <li><code>tbar</code> (top bar)</li>
        ///                                                                                                                                   <li><code>body</code></li>
        ///                                                                                                                                   <li><code>bbar</code> (bottom bar)</li>
        ///                                                                                                                                   <li><code>footer</code></li>
        ///                                                                                                                                 </ul></div>
        ///   Defaults to '<code>body</code>'.
        /// </summary>
        [JsonProperty( "elements" )]
        [DefaultValue( ( string ) null )]
        [Description( "A comma-delimited list of panel elements to initialize when the panel is rendered. Normally, this list will be generated automatically based on the items added to the panel at config time, but sometimes it might be useful to make sure a structural element is rendered even if not specified at config time (for example, you may want to add a button or toolbar dynamically after the panel has been rendered). Adding those elements to this list will allocate the required placeholders in the panel when it is rendered." )]
        public string Elements { get; set; }

        /// <summary>
        ///   Defaults to <code>false</code>.  When set to <code>true</code>, an extra css class <code>'x-panel-normal'</code>
        ///   will be added to the panel's element, effectively applying css styles suggested by the W3C
        ///   (see http://www.w3.org/TR/CSS21/sample.html) to the Panel's <b>body</b> element (not the header,
        ///   footer, etc.).
        /// </summary>
        [JsonProperty( "preventBodyReset" )]
        [DefaultValue( false )]
        [Description( "Defaults to false. When set to true, an extra css class 'x-panel-normal' will be added to the panel's element, effectively applying css styles suggested by the W3C (see http://www.w3.org/TR/CSS21/sample.html) to the Panel's body element (not the header, footer, etc.)." )]
        public bool PreventBodyReset { get; set; }

        private void PositionBars()
        {
            if ( Bbar != null )
            {
                var top = Size.Height - _bbar.Height;
                if ( this is Window )
                    top -= ( TitleBarHeight + ( BorderWidth * 2 ) + 6 );

                top -= ( BorderWidth * 2 ) - 2;

                if ( this is GridPanel )
                {
                    top -= ( BorderWidth * 4 );
                    if ( !string.IsNullOrEmpty( Title ) )
                        top -= TitleBarHeight;

                    if ( ( ( GridPanel ) this ).ColumnModel.ShouldSerializeColumns() )
                        top -= TitleBarHeight;
                }

                Bbar.Location = new Point( 0, top );
                Bbar.Size = new Size( ClientSize.Width, Bbar.Height );
            }
            PerformLayout();
        }

        private void PanelResize( object sender, EventArgs e )
        {
            PositionBars();
        }

        protected override void Dispose( bool disposing )
        {
            Resize -= PanelResize;
            base.Dispose( disposing );
        }

        ~Panel()
        {
            Dispose();
        }

        protected override void OnPaintNcArea( PaintEventArgs e )
        {
            // Caption background
            DrawTitleBar( e.Graphics,
                new Rectangle( e.ClipRectangle.X, e.ClipRectangle.Y, e.ClipRectangle.Width, this is Window ? TitleBarHeight : TitleBarHeight - 1 ) );
            DrawTools( e.Graphics, e.ClipRectangle );
            DrawTitle( e.Graphics,
                new Rectangle( e.ClipRectangle.X + ( Unstyled ? 0 : ( this is Window ? 2 : 4 ) ), e.ClipRectangle.Y + ( Unstyled ? 0 : ( this is Window ? 4 : 7 ) ), e.ClipRectangle.Width - 4,
                                      TitleBarHeight - BorderWidth ) );
            DrawFooterBar( e.Graphics,
                           new Rectangle( e.ClipRectangle.X + BorderWidth,
                                          e.ClipRectangle.Y + e.ClipRectangle.Height -
                                          ( BorderWidth + ( ButtonsBarHeight + ( this is Window ? 0 : 4 ) ) ), e.ClipRectangle.Width - ( BorderWidth * 2 ),
                                          ButtonsBarHeight + ( this is Window ? 0 : 4 ) ) );
            DrawInnerBorder( e.Graphics,
                             new Rectangle( e.ClipRectangle.X, e.ClipRectangle.Y, e.ClipRectangle.Width - BorderWidth,
                                            e.ClipRectangle.Height - BorderWidth ) );
            if ( Bbar != null )
                Bbar.OnPaintInternal( new PaintEventArgs( e.Graphics,
                                                          new Rectangle(
                                                              e.ClipRectangle.X +
                                                              ( BorderWidth + ( this is Window ? 4 : 0 ) ),
                                                              e.ClipRectangle.Height - Bbar.Height -
                                                              ( BorderWidth + ( this is Window ? 2 : 0 ) ),
                                                              e.ClipRectangle.Width -
                                                              ( ( BorderWidth * 2 ) + ( this is Window ? 9 : 0 ) ),
                                                              Bbar.Height ) ) );
        }

        /// <summary>
        ///   Internal method to draw panel frame border
        /// </summary>
        /// <param name = "g">Graphics instance of non client area.</param>
        /// <param name = "bounds">The bounds in wich the frame will be drawn.</param>
        internal virtual void DrawInnerBorder( Graphics g, Rectangle bounds )
        {
            if ( !Border || Unstyled )
                return;
            if ( this is Window )
            {
                bounds.Inflate( -4, -4 );
                bounds.Offset( 0, TitleBarHeight - 6 );
                if ( DrawButtonsBar )
                {
                    bounds.Height -= ButtonsBarHeight + TitleBarHeight - 6 - ( BorderWidth * 2 );
                }
                bounds = ClientRectangle;
                bounds.Offset( 6, TitleBarHeight );
                bounds.Width += 1;
                bounds.Height += 1;
            }
            else
            {
                if ( DrawButtonsBar )
                    bounds.Height -= ( ButtonsBarHeight + 5 );
            }
            using ( var pen = new Pen( FrameBorderColor ) )
            {
                g.DrawRectangle( pen, bounds );
            }
        }

        /// <summary>
        ///   Internal method to draw the title bar.
        /// </summary>
        /// <param name = "g">Graphics instance of non client area.</param>
        /// <param name = "bounds">The bounds to draw in.</param>
        internal virtual void DrawTitleBar( Graphics g, Rectangle bounds )
        {
            if ( Parent != null && Parent is Container && ( ( Container ) Parent ).Layout == LayoutType.Card )
                return;

            if ( !Unstyled && ( !string.IsNullOrEmpty( Title ) || this is Window || Layout == LayoutType.Card ) )
            {
                var topLine = Color.FromArgb( 243, 247, 251 );
                var middleLine = Color.FromArgb( 171, 199, 236 );
                var topStart = Color.FromArgb( 218, 231, 236 );
                var topEnd = Color.FromArgb( 205, 222, 243 );
                var bottomStart = Color.FromArgb( 184, 207, 238 );
                var bottomEnd = Color.FromArgb( 203, 221, 243 );

                if ( this is Window )
                {
                    using ( var br = new SolidBrush( PanelNCBackgroundColor ) )
                    {
                        g.FillRectangle( br, bounds.X, bounds.Y, bounds.Width, bounds.Height );
                    }
                }
                else
                {
                    if ( Parent != null )
                    {
                        var containerParent = Parent as Container;
                        if ( containerParent != null )
                            if ( containerParent.Layout == LayoutType.Card )
                                return;
                    }
                    if ( Layout != LayoutType.Card )
                    {
                        using ( var brush = new LinearGradientBrush(
                            new Rectangle( bounds.X + BorderWidth, bounds.Y + BorderWidth,
                                           bounds.Width - ( BorderWidth * 2 ), ( TitleBarHeight - 1 ) + BorderWidth ),
                            topStart,
                            bottomEnd, LinearGradientMode.Vertical ) )
                        {
                            var blend = new ColorBlend( 6 );
                            blend.Colors[ 0 ] = topLine;
                            blend.Colors[ 1 ] = topStart;
                            blend.Colors[ 2 ] = topEnd;
                            blend.Colors[ 3 ] = middleLine;
                            blend.Colors[ 4 ] = bottomStart;
                            blend.Colors[ 5 ] = bottomEnd;
                            blend.Positions = new[] { 0.0f, 0.01f, 0.49f, 0.5f, 0.51f, 1.0f };
                            brush.InterpolationColors = blend;
                            g.FillRectangle( brush, bounds.X + BorderWidth, bounds.Y + BorderWidth,
                                             bounds.Width - ( BorderWidth * 2 ), ( TitleBarHeight - 1 ) + BorderWidth );
                        }
                    }
                    else
                    {
                        if ( null == Items )
                            return;
                        var backgroundColor = Color.FromArgb( 206, 217, 231 );
                        using ( var br = new SolidBrush( backgroundColor ) )
                        {
                            g.FillRectangle( br,
                                             new Rectangle( bounds.X + BorderWidth, bounds.Y + BorderWidth,
                                                            bounds.Width - ( BorderWidth * 2 ),
                                                            TitleBarHeight + BorderWidth ) );
                        }
                        var childrens = Items.OfType<Panel>();
                        if ( childrens.Count() > 0 )
                        {
                            var foreTabColor = Color.FromArgb( 206, 223, 245 );
                            var backTabsColor = Color.FromArgb( 222, 236, 253 );
                            var index = 0;
                            var borderPadding = 3;
                            var tabPadding = 0;

                            using ( var pen = new Pen( FrameBorderColor ) )
                            {
                                g.DrawLine( pen, bounds.X,
                                            bounds.Y + TitleBarHeight - 3,
                                            bounds.X + BorderWidth + bounds.Width - ( BorderWidth * 2 ),
                                            bounds.Y + TitleBarHeight - 3 );

                                //g.DrawLine( pen, bounds.X,
                                //            bounds.Y + TITLE_BAR_HEIGHT + BorderWidth,
                                //            bounds.X + BorderWidth + bounds.Width - ( BorderWidth * 2 ),
                                //            bounds.Y + TITLE_BAR_HEIGHT + BorderWidth );
                            }

                            bounds.Inflate( -BorderWidth, -BorderWidth );

                            using ( var br = new SolidBrush( backTabsColor ) )
                            {
                                g.FillRectangle( br,
                                                 new Rectangle( bounds.X + BorderWidth, bounds.Y + TitleBarHeight - 2,
                                                                bounds.Width - ( BorderWidth * 2 ),
                                                                TitleBarHeight + TitleBarHeight - 1 ) );
                            }

                            foreach ( var children in childrens )
                            {
                                var childRect =
                                    RoundedRectangle.Create( tabPadding + ( 80 * index ) + bounds.X + borderPadding,
                                                             bounds.Y + 2, 80,
                                                             TitleBarHeight - 6, 3,
                                                             RoundedRectangle.RectangleCorners.TopLeft |
                                                             RoundedRectangle.RectangleCorners.TopRight );
                                using ( var pen = new Pen( FrameBorderColor ) )
                                {
                                    g.DrawPath( pen, childRect );
                                }
                                childRect =
                                    RoundedRectangle.Create( tabPadding + ( 80 * index ) + bounds.X + borderPadding + 1,
                                                             bounds.Y + 3, 78,
                                                             TitleBarHeight - 8, 3,
                                                             RoundedRectangle.RectangleCorners.TopLeft |
                                                             RoundedRectangle.RectangleCorners.TopRight );

                                if ( index == ActiveItem )
                                {
                                    using (
                                        var br =
                                            new LinearGradientBrush(
                                                new Rectangle(
                                                    tabPadding + ( 80 * index ) + bounds.X + borderPadding + 1,
                                                    bounds.Y + 3, 78,
                                                    TitleBarHeight - 8 ), Color.White, foreTabColor,
                                                LinearGradientMode.Vertical ) )
                                    {
                                        g.FillPath( br, childRect );
                                    }

                                    using ( var pen = new Pen( foreTabColor ) )
                                    {
                                        g.DrawLine( pen, tabPadding + borderPadding + 2 + ( 80 * index ),
                                                    bounds.Y + 2 + TitleBarHeight - 6,
                                                    tabPadding + 80 + borderPadding + ( 80 * index ),
                                                    bounds.Y + 2 + TitleBarHeight - 6 );
                                    }
                                }
                                else
                                {
                                    using (
                                        var br =
                                            new LinearGradientBrush(
                                                new Rectangle(
                                                    tabPadding + ( 80 * index ) + bounds.X + borderPadding + 1,
                                                    bounds.Y + 3, 78,
                                                    TitleBarHeight - 8 ), foreTabColor, backTabsColor,
                                                LinearGradientMode.Vertical ) )
                                    {
                                        g.FillPath( br, childRect );
                                    }
                                }


                                if ( !string.IsNullOrWhiteSpace( children.Title ) )
                                {
                                    using (
                                        var font = new Font( "Tahoma", 11,
                                                             index == ActiveItem ? FontStyle.Bold : FontStyle.Regular,
                                                             GraphicsUnit.Pixel ) )
                                    {
                                        using ( var br = new SolidBrush( TitleFontColor ) )
                                        {
                                            var sf = new StringFormat
                                                         {
                                                             LineAlignment = StringAlignment.Center,
                                                             Alignment = StringAlignment.Center,
                                                             Trimming = StringTrimming.Character
                                                         };
                                            //var textSize = g.MeasureString( children.Title, font );
                                            g.DrawString( children.Title, font, br,
                                                          new Rectangle(
                                                              tabPadding + ( 80 * index ) + bounds.X + borderPadding + 1,
                                                              bounds.Y + 5, 78,
                                                              TitleBarHeight - 8 ), sf );
                                        }
                                    }
                                }


                                index++;
                                if ( tabPadding == 0 )
                                    tabPadding = 3;
                            }

                            bounds.Inflate( BorderWidth, BorderWidth );
                        }
                    }
                    using ( var pen = new Pen( FrameBorderColor ) )
                    {
                        var topBorderWidth = Border ? 1 : -1;
                        g.DrawLine( pen, bounds.X + BorderWidth,
                            bounds.Y + ( this is Window ? TitleBarHeight : TitleBarHeight - 1 ) + BorderWidth + topBorderWidth,
                                    bounds.X + BorderWidth + bounds.Width - ( BorderWidth * 2 ),
                                    bounds.Y + ( this is Window ? TitleBarHeight : TitleBarHeight - 1 ) + BorderWidth + topBorderWidth );
                    }
                }
            }
            else if ( Unstyled )
            {
                using ( var br = new SolidBrush( Parent.BackColor ) )
                {
                    g.FillRectangle( br,
                                     new Rectangle( bounds.X, bounds.Y,
                                                    bounds.Width,
                                                    TitleBarHeight + 1 ) );
                }
            }
        }

        /// <summary>
        ///   Internal method to draw the title.
        /// </summary>
        /// <param name = "g">Graphics instance of non client area.</param>
        /// <param name = "bounds">The bounds to draw in.</param>
        internal virtual void DrawTitle( Graphics g, Rectangle bounds )
        {
            if ( Parent != null && ( Parent as Container != null ) && ( Parent as Container ).Layout == LayoutType.Card )
                return;
            if ( !string.IsNullOrWhiteSpace( Title ) && Layout != LayoutType.Card )
            {
                using ( var br = new SolidBrush( Unstyled ? Color.Black : TitleFontColor ) )
                {
                    var sf = new StringFormat
                                 {
                                     LineAlignment = StringAlignment.Near,
                                     Trimming = StringTrimming.Character
                                 };
                    //var textSize = g.MeasureString( Title, font );
                    if ( this is Window )
                        bounds.Y -= 1;
                    //    g.DrawString( Title, font, br, bounds.X + 5, bounds.Y + 2 + ( TITLE_BAR_HEIGHT / 2 ) - textSize.Height / 2 );
                    //else
                    g.DrawString( Title, Unstyled ? UnstyledTitleFont : TitleFont, br, bounds, sf );
                    //g.DrawString( Title, font, br, bounds.X + 2, bounds.Y - 5 + ( TITLE_BAR_HEIGHT / 2 ) - textSize.Height / 2 );
                }
            }
        }

        /// <summary>
        ///   Internal method to draw the footer bar and the buttons in it.
        /// </summary>
        /// <param name = "g">Graphics instance of non client area.</param>
        /// <param name = "bounds">The bounds to draw in.</param>
        /// <param name = "setLocation">If true the position of the buttons will be updated.</param>
        protected virtual void DrawFooterBar( Graphics g, Rectangle bounds, bool setLocation = true )
        {
            if ( !DrawButtonsBar )
                return;

            var oldColor = PanelNCBackgroundColor;
            if ( !( this is Window ) )
            {
                PanelNCBackgroundColor = Parent != null ? Parent.BackColor : Color.FromArgb( 223, 232, 246 );
            }
            var leftRightBorder = this is Window ? 3 : -1;
            using ( var br = new SolidBrush( PanelNCBackgroundColor ) )
            {
                //g.FillRectangle( br, bounds.X + leftRightBorder, bounds.Y + ( this is Window ? BorderWidth : 0 ), bounds.Width - ( leftRightBorder * 2 ), BUTTONS_BAR_HEIGHT - ( this is Window ? BorderWidth : 0 ) );
                g.FillRectangle( br, bounds.X + leftRightBorder, bounds.Y - ( this is Window ? 4 : 3 ),
                                 bounds.Width - ( leftRightBorder * 2 ), ButtonsBarHeight + ( this is Window ? 0 : 8 ) );
            }

            //var rightStart = Bounds.Right - 37;
            //if ( !( this is Window ) )
            //    rightStart += 28;

            var index = 0;
            var buttons = Buttons;
            var topShift = ( ( this is Window ) ? 2 : 1 ) + ( BorderWidth * 2 );
            var rightShift = ( ( this is Window ) ? 10 : 2 ) + ( BorderWidth * 2 );
            foreach ( var button in buttons )
            {
                var pos = new Rectangle( Bounds.Width - ( button.Width * ( index + 1 ) ) - ButtonPadding -
                                         ( rightShift + ( ButtonPadding * ( index ) ) ),
                                         Bounds.Height - ( ButtonsBarHeight / 2 ) - ( button.Height / 2 ) - topShift,
                                         button.Width,
                                         button.Height );
                var pe = new PaintEventArgs( g, pos );
                if ( setLocation )
                {
                    var locationTopShift = ( ( this is Window ) ? button.Height + 1 : button.Height + 2 ) + ( BorderWidth * 2 );
                    //var locationTopShift = ( ( this is Window ) ? button.Height : 4 ) + ( BorderWidth * 2 );
                    var locationRightShift = ( this is Window ) ? 7 : 1;
                    var bLocation = new Point( pos.X - locationRightShift, pos.Y - locationTopShift );
                    //var bLocation =
                    //    new Point(
                    //        Bounds.Width - ( button.Width * ( index + 1 ) ) - ( ButtonPadding * 2 ) -
                    //        ( rightShift + ( ButtonPadding * index ) ),
                    //        Bounds.Height - ( BUTTONS_BAR_HEIGHT / 2 ) - ( button.Height / 2 ) - topShift - button.Height - locationTopShift );
                    if ( !bLocation.Equals( button.Location ) )
                        button.Location = bLocation;
                }

                button.OnPaintInternal( pe );

                //rightStart -= ( button.Width + ButtonPadding );
                index++;
            }

            if ( !( this is Window ) )
            {
                PanelNCBackgroundColor = oldColor;
            }
        }

        protected void DrawTools( Graphics g, Rectangle bounds )
        {
            var index = 0;
            var rightShift = this is Window ? 17 : Unstyled ? 15 : 19;
            var topShift = this is Window ? 3 : Unstyled ? 0 : 6;
            if ( Closable )
            {
                g.DrawImage( Resources.Close, bounds.Width - ( ( index++ * 16 ) + rightShift ), bounds.Y + topShift, 15, 15 );
            }
            if ( this is Window )
            {
                var window = this as Window;
                if ( window != null )
                {
                    if ( window.Maximizable )
                        g.DrawImage( Resources.Maximize, bounds.Width - ( ( index++ * 16 ) + rightShift ),
                                     bounds.Y + topShift,
                                     15, 15 );

                    if ( window.Minimizable )
                        g.DrawImage( Resources.Minimize, bounds.Width - ( ( index++ * 16 ) + rightShift ),
                                     bounds.Y + topShift,
                                     15, 15 );
                }
            }
            if ( Collapsible )
                g.DrawImage( Resources.Collapse, bounds.Width - ( ( index * 16 ) + rightShift ), bounds.Y + topShift,
                             15, 15 );
        }

        /// <summary>
        ///   Internal method to get a button in the footer bar.
        /// </summary>
        /// <param name = "pt">The Point to check.</param>
        /// <returns>The instance of the button if found otherwise null.</returns>
        internal ButtonLW GetButtonAtPoint( Point pt )
        {
            return DrawButtonsBar ? Buttons.FirstOrDefault( button => button.Bounds.Contains( pt ) ) : null;
        }

        internal override BaseComponent GetComponentAtPoint( Point pt )
        {
            var comp = base.GetComponentAtPoint( pt );
            if ( comp == null && Bbar != null && Bbar.Bounds.Contains( pt ) )
            {
                comp = Bbar.GetComponentAtPoint( new Point( pt.X, pt.Y - ClientSize.Height ) );
            }
            return comp ?? GetButtonAtPoint( pt );
        }

        protected override void OnNonClientAreaCalcSize( ref Rectangle bounds, bool update )
        {
            var bottomWidth = Bbar != null ? Bbar.Height : 0;
            var topWidth = ( !string.IsNullOrWhiteSpace( Title ) || Layout == LayoutType.Card )
                ? ( this is Window ? TitleBarHeight : TitleBarHeight - 1 ) + ( BorderWidth * 2 ) + 1
                               : BorderWidth;

            if ( Parent != null && ( Parent as Container != null ) && ( Parent as Container ).Layout == LayoutType.Card )
            {
                topWidth = BorderWidth;
            }

            var clientPadding = new Padding( BorderWidth, topWidth, BorderWidth,
                                             ( DrawButtonsBar ? ( this is Window ? ButtonsBarHeight + 3 : ButtonsBarHeight + 4 ) : -1 ) + ( BorderWidth * 2 ) +
                                             bottomWidth );
            bounds = new Rectangle( bounds.Left + clientPadding.Left, bounds.Top + clientPadding.Top,
                                    bounds.Width - clientPadding.Horizontal, bounds.Height - clientPadding.Vertical );
        }

        protected override void OnPaintBackground( PaintEventArgs pevent )
        {
            if ( Unstyled )
            {
                var color = Parent != null ? Parent.BackColor : BackColor;
                using ( var br = new SolidBrush( color ) )
                {
                    pevent.Graphics.FillRectangle( br, pevent.ClipRectangle );
                }
            }
            else
            {
                base.OnPaintBackground( pevent );
            }
        }

        public bool ShouldSerializeTools()
        {
            return _toolsInternal.Count > 0;
        }

        protected void ResetTools()
        {
            _toolsInternal.Clear();
        }

        public bool ShouldSerializePadding()
        {
            return Padding.All == -1 || Padding.All > 0;
        }

        protected void ResetPadding()
        {
            Padding = Padding.Empty;
        }
    }
}